package com.ruoyi.workflow.service.impl;

import java.io.InputStream;
import java.io.Serializable;
import java.util.List;
import java.util.zip.ZipInputStream;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUtils;

import com.ruoyi.system.service.ISysDictTypeService;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.image.ProcessDiagramGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.workflow.mapper.BpmnInfoMapper;
import com.ruoyi.workflow.domain.BpmnInfo;
import com.ruoyi.workflow.service.IBpmnInfoService;
import org.springframework.transaction.annotation.Transactional;

/**
 * 流程定义Service业务层处理
 *
 * @author god磊
 * @since 2022-11-14
 */
@Service
@Slf4j
public class BpmnInfoServiceImpl extends ServiceImpl<BpmnInfoMapper, BpmnInfo> implements IBpmnInfoService {

    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private ISysDictTypeService dictTypeService;
    @Autowired
    private ProcessDiagramGenerator processDiagramGenerator;

    @Override
    public BpmnInfo getById(Serializable id) {
        BpmnInfo bpmnInfo = super.getById(id);
        if (bpmnInfo == null) {
            throw new ServiceException("参数错误，流程信息不存在");
        }
        return bpmnInfo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deploy(InputStream fileData, BpmnInfo bpmnInfo) {
        // 1. 获取流程定义的类型标签
        List<SysDictData> dictDataList = dictTypeService.selectDictDataByType("sys_audit_type");
        for (SysDictData data : dictDataList) {
            // 当前字典的值是否为当前流程类型的值
            if (data.getDictValue().equals(bpmnInfo.getBpmnType())) {
                bpmnInfo.setBpmnLabel(data.getDictLabel());
                break;
            }
        }
        Deployment deployment;
        String suffix = FileUtils.getSuffix(bpmnInfo.getResourceName());
        // 进行activiti 部署
        if ("zip".equals(suffix)) {
            deployment = repositoryService.createDeployment().addZipInputStream(new ZipInputStream(fileData))
                    .name(bpmnInfo.getBpmnLabel())
                    .deploy();

        } else {
            deployment = repositoryService.createDeployment().addInputStream(bpmnInfo.getResourceName(), fileData)
                    .name(bpmnInfo.getBpmnLabel())
                    .deploy();
        }
        String definitionKey = bpmnInfo.getBpmnType();
        bpmnInfo.setDeployTime(deployment.getDeploymentTime());
        bpmnInfo.setProcessDefinitionKey(definitionKey);
        // 基于流程定义key 查询流程定义对象
        ProcessDefinition definition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(definitionKey)
                .deploymentId(deployment.getId())
                .singleResult();
        bpmnInfo.setVersion((long) definition.getVersion());
        bpmnInfo.setDeploymentId(definition.getDeploymentId());
        super.save(bpmnInfo);
    }

    @Override
    public List<BpmnInfo> selectBpmnInfoList(BpmnInfo bpmnInfo) {
        return super.getBaseMapper().selectBpmnInfoList(bpmnInfo);
    }
    @Override
    public boolean deleteDefinition(List<Long> asList) {
        // 1. 基于流程信息 id 查询到流程信息对象
        for (Long id : asList) {
            BpmnInfo bpmnInfo = this.getById(id);
            try {
                // 2. 基于流程信息中的部署 id, 调用 activiti 的 api 来删除部署信息
                repositoryService.deleteDeployment(bpmnInfo.getDeploymentId());
            } catch (Exception e) {
                log.error(String.valueOf(e));
                // 3. 如果删除失败, 提示前端有正在进行中的流程, 无法删除
                throw new ServiceException("删除失败，当前存在正在进行的审核流程");
            }
        }
        // 4. 批量删除 bpmnInfo 的数据
        return super.removeBatchByIds(asList);
    }

    @Override
    public InputStream getResourceByType(Long id, String type) {
//        1. 基于流程信息id查询流程信息对象
        BpmnInfo bpmnInfo = this.getById(id);
//        2. 基于流程部署id查询流程定义对象
        ProcessDefinition definition = repositoryService.createProcessDefinitionQuery()
                .deploymentId(bpmnInfo.getDeploymentId())
                .singleResult();
//        3. 判断当前要查询数据的类型
        //        4. 如果当前类型是 image, 就查询流程图
        if ("image".equals(type)) {
            //        4.1 通过流程定义对象的图片资源名称, 判断是否有图片资源
//        4.2 如果有图片, 直接通过仓库 Service 接口获取图片流对象并返回
//        4.3 如果没有图片, 通过流程图生成工具, 生成流程图, 得到流对象并返回
            if (StringUtils.isNotEmpty(definition.getDiagramResourceName())) {
                return repositoryService.getResourceAsStream(bpmnInfo.getDeploymentId(), definition.getDiagramResourceName());
            } else {
                BpmnModel bpmnModel = repositoryService.getBpmnModel(definition.getId());
                return processDiagramGenerator.generateDiagram(bpmnModel,"宋体","宋体","宋体");
            }
        } else if ("bpmn".equals(type)) {
            //        5. 如果类型是 xml, 直接通过仓库 Service 获取文件流对象并返回
            if (StringUtils.isNotEmpty(definition.getResourceName())) {
                return repositoryService.getResourceAsStream(bpmnInfo.getDeploymentId(), definition.getResourceName());
            }
        } else {
            //        6. 如果是其他类型, 直接报错提示不支持的类型
            throw new ServiceException("当前查看的文件的类型不支持");
        }
        return null;
    }

}
